﻿using System;
using System.Collections.Generic;
using System.IO.Packaging;
using System.IO;
using System.Text;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using D = DocumentFormat.OpenXml.Drawing;
using P = DocumentFormat.OpenXml.Presentation;
using DocumentFormat.OpenXml;
using Fantom.Models;
namespace Fantom.Builders
{
	/// <summary>
	/// 用于演示文稿的整体导入。
	/// </summary>
	internal static class PresentationLoader
	{

		private static void RaiseLoadingSlideEvent(Presentations press, PresentationsLoadingOperationEnum loadingState, int steps, int step)
		{
			press.RaiseLoadingSlideEvent(loadingState, steps, step);
		}

		private static bool IsUriValid(Presentations press, string uristr)
		{
			return File.Exists(uristr) && !press._filePathHashSet.Contains(uristr);
		}

		/// <summary>
		/// 导入并返回演示文稿。
		/// </summary>
		/// <param name="press"></param>
		/// <param name="uristr"></param>
		/// <param name="allowEdit"></param>
		/// <returns></returns>
		public static IPresentation Load(Presentations press, string uristr, bool allowEdit)
		{
			uristr = uristr.Trim();
			if (File.Exists(uristr))
				return LoadMain(press, uristr, allowEdit);
			else
				return null;
		}

		/// <summary>
		/// 实际的导入模块。
		/// </summary>
		/// <param name="press"></param>
		/// <param name="uristr"></param>
		/// <param name="allowEdit"></param>
		/// <returns></returns>
		private static IPresentation LoadMain(Presentations press, string uristr, bool allowEdit)
		{

			var app = press.Application;
			var stepcount = 0;
			var step = 0;

			var presdoc = PresentationDocument.Open(uristr, !allowEdit);

			var package = presdoc.Package;

			var pres = PresentationBuilder.Build(presdoc, uristr, allowEdit);

			var sldps = presdoc.PresentationPart.SlideParts;

			press._filePathHashSet.Add(uristr);

			stepcount = sldps.Count() + 4;

			// 截止目前为止，演示文稿的导入已经完成。
			RaiseLoadingSlideEvent(press, PresentationsLoadingOperationEnum.PackageLoadComplete, stepcount, ++step);

			// 导入主题。
			var theme = (pres as Presentation).Theme =
				ThemeBuilder.Build(presdoc.PresentationPart.ThemePart.Theme);

			// 导入主题完成。
			RaiseLoadingSlideEvent(press, PresentationsLoadingOperationEnum.ThemeLoadComplete, stepcount, ++step);

			// 幻灯片重排。
			var sldrange = from sld in sldps
						   orderby SlideBuilder.GetSlideId(sld.Uri.OriginalString)
						   select sld;

			// 获得空的幻灯片集合。
			var slides = pres.Slides as Slides;

			// 幻灯片的重排已完成。
			RaiseLoadingSlideEvent(press, PresentationsLoadingOperationEnum.SlidesReorderComplete, stepcount, ++step);

			// 幻灯片处理。
			foreach (var sldp in sldrange)
			{
				LoadSlides(package, app, pres, slides, sldp);

				// 单页幻灯片导入完成。
				RaiseLoadingSlideEvent(press, PresentationsLoadingOperationEnum.SlideIndexComplete, stepcount, ++step);
			}

			presdoc.Close();
			presdoc.Dispose();

			(pres as Presentation).Parent = press; // 绑定父子集合关系。

			// 此时文档全部导入完成。
			RaiseLoadingSlideEvent(press, PresentationsLoadingOperationEnum.SlideLoadComplete, stepcount, ++step);

			return pres;
		}

		/// <summary>
		/// 导入幻灯片。
		/// </summary>
		/// <param name="package"></param>
		/// <param name="app"></param>
		/// <param name="pres"></param>
		/// <param name="slides"></param>
		/// <param name="sldp"></param>
		private static void LoadSlides(Package package, IApplication app, IPresentation pres, Slides slides, SlidePart sldp)
		{
			var xsld = sldp.Slide;
			var csld = xsld.CommonSlideData;
			var xtiming = GetTiming(xsld);

			var newsld = SlideBuilder.Build(sldp) as Slide;
			var shps = newsld.Shapes as Shapes;

			var uridic = new Dictionary<string, Uri>();

			foreach (var idpair in sldp.Parts)
				uridic.Add(idpair.RelationshipId, idpair.OpenXmlPart.Uri);

			// 自定义Xml与自定义Tag被设计在这个节点中。
			var xcustomlist = csld.GetFirstChild<P.CustomerDataList>();

			// 为幻灯片载入自定义信息。
			LoadCustomInfo(app, newsld, package, xcustomlist, uridic, sldp);

			shps.Application = app;
			shps.Parent = newsld;

			// 为每一页读入图形信息。
			foreach (var shpe in csld.ShapeTree.Skip(2))
			{
				LoadShape(package, uridic, app, sldp, shps, shpe, pres.Theme as Theme, pres.MediaManager as MediaManager);
			}

			// 导入时间轴。
			LoadTimeLine(newsld, shps, app, xtiming, pres.Theme as Theme, pres.MediaManager as MediaManager);

			slides.Add(newsld);

			newsld.Application = app;
			newsld.Parent = pres.Slides;

		}

		/// <summary>
		/// 导入图形。
		/// </summary>
		private static void LoadShape(
			Package package,
			Dictionary<string, Uri> uridic,
			IApplication app,
			SlidePart sldp,
			Shapes shps,
			OpenXmlElement shpe,
			Theme theme,
			MediaManager mediaManager)
		{
			var newshp = ShapeBuilder.Build(sldp, shpe, theme, mediaManager) as Shape;
			if (newshp == null) return;

			newshp.Application = app;
			newshp.Parent = shps;
			shps.Add(newshp);

			var xshpcustomlist =
				shpe.FirstChild.ChildElements[2].GetFirstChild<P.CustomerDataList>();
			LoadCustomInfo(app, newshp, package, xshpcustomlist, uridic, sldp);

			if (newshp.Type != ShapeType.Common) return;

			(newshp.TextBody as TextBody).Application = newshp.Application;
			(newshp.TextBody as TextBody).Parent = newshp;

			foreach (var para in shpe.GetFirstChild<P.TextBody>().Elements<D.Paragraph>())
			{
				LoadTextRange(sldp, newshp, para, theme, mediaManager);
			}

		}

		// 导入字体相关设置。
		private static void LoadTextRange(
			SlidePart sldp,
			Shape shp,
			 D.Paragraph para,
			Theme theme,
			MediaManager mediaManager)
		{
			var newpara = TextParagraphBuilder.Build(para) as TextParagraph;

			foreach (var run in para.Elements<D.Run>())
			{
				var newblock = TextBlockBuilder.Build(sldp, run, theme, mediaManager) as TextBlock;

				newpara.Add(newblock);

				newblock.Application = shp.Application;
				newblock.Parent = newpara;
			}

			(shp.TextBody as TextBody).Add(newpara);

			newpara.Application = shp.Application;
			newpara.Parent = shp.TextBody;
		}

		// 提取时间节点。
		private static P.Timing GetTiming(P.Slide slide)
		{
			var timing = (P.Timing)null;
			// Console.WriteLine(sld.Slide.OuterXml);
			var alterContent = slide.GetFirstChild<AlternateContent>();

			if (alterContent != null)
			{
				var choice = alterContent.GetFirstChild<AlternateContentChoice>();
				if (choice != null)
				{
					timing = choice.GetFirstChild<P.Timing>();
				}
			}
			else
			{
				timing = slide.GetFirstChild<P.Timing>();
			}
			return timing;
		}

		// 导入时间轴动画数据。
		private static void LoadTimeLine(Slide slide, Shapes shps, IApplication app, P.Timing timing, Theme theme, MediaManager mediaManager)
		{
			var timeLine = TimeLineBuilder.Build(app, slide, timing, shps, theme, mediaManager);

			slide.TimeLine = timeLine;
		}

		// 载入自定义信息。
		// 自定义信息包括自定义Xml与自定义Tag。
		private static void LoadCustomInfo(IApplication app, ICustomContainer container, Package package, P.CustomerDataList xlist, Dictionary<string, Uri> uridic, SlidePart sldpart)
		{

			// 自定义列表。
			var customList = container.CustomXmlList as CustomXmlList;
			var tags = container.Tags; // 获得父对象的Tags容器并使用它，添加字段。

			customList.Application = app;
			customList.Parent = container;

			if (xlist == null) return;

			// 遍历Xml节点。
			foreach (var customXmlPart in xlist)
			{

				// 处理自定义Xml节点。
				if (customXmlPart is P.CustomerData)
				{
					var xmlpart = CustomXmlBuilder.Build(
						customXmlPart as P.CustomerData, package, uridic) as CustomXml;
					xmlpart.Application = app;
					xmlpart.Parent = customList;
					customList.Add(xmlpart);
				}

				// 处理自定义Tag节点。
				else if (customXmlPart is P.CustomerDataTags)
				{
					string rId = (customXmlPart as P.CustomerDataTags).Id;
					var t =
						from tagpair in sldpart.UserDefinedTagsParts
						where tagpair.Uri == uridic[rId]
						select tagpair;
					if (t.Count() != 0)
					{
						var taglist = t.First().TagList;
						foreach (P.Tag tag in taglist)
						{
							container.Tags.Add(tag.Name, tag.Val);
						}
					}
				}

			}
		}

	}
}
